package com.tencent.cloud.iov.block;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
 * @author showxiao
 * @date 2018/5/10
 */

public class AnnotationBlockFactory implements IBlockLayoutFactory {

    private static final String CLASS_NAME_POSTFIX = "$LayoutFactory";
    private static final String METHOD_NAME = "create";

    private Map<Class<?>, Method> mCachedFactoryMethods = new HashMap<>();

    @Override
    public <T> IBlockLayout<T> create(Class<? extends T> itemClass) {
        Method method = mCachedFactoryMethods.get(itemClass);
        if (method == null) {
            method = getGeneratedFactoryMethod(itemClass);

            if (method != null) {
                if (!method.isAccessible()) {
                    method.setAccessible(true);
                }

                mCachedFactoryMethods.put(itemClass, method);
            }
        }

        if (method != null) {
            try {
                return (IBlockLayout<T>) method.invoke(null, itemClass);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }

        throw new IllegalStateException("Missing BlockLayout for " +
                itemClass + ": is @Block annotation missed?");
    }

    private Method getGeneratedFactoryMethod(Class clazz) {
        String name = clazz.getName();
        try {
            // 查找当前类
            Class<?> generatedClass = Class.forName(name + CLASS_NAME_POSTFIX);
            return generatedClass.getDeclaredMethod(METHOD_NAME, Class.class);
        } catch (ClassNotFoundException e) {
            // 查找接口
            Class<?>[] interfaces = clazz.getInterfaces();
            if (interfaces != null && interfaces.length > 0) {
                for (Class<?> inter : interfaces) {
                    Method method = getGeneratedFactoryMethod(inter);
                    if (method != null) {
                        return method;
                    }
                }
            }

            // 配查找父类
            Class<?> superclass = clazz.getSuperclass();
            if (superclass != null) {
                Method method = getGeneratedFactoryMethod(superclass);
                if (method != null) {
                    return method;
                }
            }

        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

        return null;
    }
}
